package com.alan.netty.nio.demo;

import org.springframework.util.StringUtils;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.*;

/**
 * @author weiBin
 * @date 2018/11/8
 */
public class NioEchoClientHandler implements Runnable {
    private Selector selector;
    private SocketChannel sc;
    private String host;
    private int port;
    private volatile boolean stop = false;
    private ExecutorService executorService;

    public NioEchoClientHandler(String host, int port) {
        try {
            this.host = StringUtils.isEmpty(host) ? "127.0.0.1" : host;
            this.port = port;
            executorService = new ThreadPoolExecutor(1, 1,
                    0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>());
            selector = Selector.open();
            sc = SocketChannel.open();
            sc.configureBlocking(false);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    public void stop() {
        stop = true;
    }

    @Override
    public void run() {
        try {
            sc.register(selector, SelectionKey.OP_CONNECT);
            sc.connect(new InetSocketAddress(host, port));
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
        while (!stop) {
            try {
//                间隔1s查询就绪的channel
                if (selector.select(1000L) == 0) {
                    //没有就绪的跳过
                    continue;
                }
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> keyIterator = keys.iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();
                    //移除当前监听
                    keyIterator.remove();
                    try {
                        inputHandler(key);
                    } catch (Exception e) {
                        e.printStackTrace();
                        if (null != key) {
                            key.cancel();
                            if (null != key.channel()) {
                                key.channel().close();
                            }
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                System.exit(1);
            }
        }
        if (null != selector) {
            try {
                selector.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (null != executorService) {
            executorService.shutdown();
        }
    }

    private void inputHandler(SelectionKey key) throws IOException {
        if (key.isValid()) {
            SocketChannel sc = (SocketChannel) key.channel();
            //连接模式
            if (key.isConnectable()) {
                //是否连接成功
                if (sc.finishConnect()) {
                    System.out.println("连接到服务器......");
                    System.out.println("请输入消息[输入\"Quit\"]退出：");
                    executorService.submit(() -> {
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        while (true) {
                            try {
                                buffer.clear();
                                Scanner scanner = new Scanner(System.in);
                                String msg = scanner.next();
                                if (msg.equals("Quit")) {
                                    System.out.println("关闭客户端......");
                                    key.cancel();
                                    sc.close();
                                    this.stop = true;
                                    break;
                                }
                                buffer.put(msg.getBytes("UTF-8"));
                                buffer.flip();
                                sc.write(buffer);
                                System.out.println("请输入消息[输入\"Quit\"]退出：");
                            } catch (IOException e) {
                                e.printStackTrace();

                            }
                        }
                    });
                    sc.register(selector, SelectionKey.OP_READ);
                } else {
                    // 连接失败，进程退出
                    System.exit(1);
                }
            }
            //读模式
            if (key.isReadable()) {
                ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                int read = sc.read(readBuffer);
                if (read > 0) {
                    readBuffer.flip();
                    byte[] bytes = new byte[readBuffer.remaining()];
                    readBuffer.get(bytes);
                    String body = new String(bytes, "UTF-8");
                    System.out.println(body);

                    if (body.equals("Quit")) {
                        this.stop = true;
                    }
                } else if (read < 0) {
                    System.out.println("关闭端链路");
                    key.cancel();
                    sc.close();
                } else {

                }
            }
            //写模式
            if (key.isWritable()) {
                System.out.println("The key is writable");
            }
        }
    }
}
